/*
 * w25q16.c
 *  该模块用于对w25q16进行读写操作
 *  Created on: 2025.6.10
 *      Author: TracyHenry
 *  注意，所有16位数据都按照大端模式存储，即高位在地址低位，低位在地址高位
 */
#include "w25q16.h"
#include "spi.h"

// 根据你的硬件设计修改CS引脚和端口
#define CS_LOW()    HAL_GPIO_WritePin(w25q16_cs_GPIO_Port, w25q16_cs_Pin, GPIO_PIN_RESET)
#define CS_HIGH()   HAL_GPIO_WritePin(w25q16_cs_GPIO_Port, w25q16_cs_Pin, GPIO_PIN_SET)

/******************************************************************************
 * FunctionName : W25Q16_SendByte
 * Description  : 向W25Q16发送一个字节的数据
 * Parameters   : uint8_t byte
 * Returns      : void
*******************************************************************************/
void W25Q16_SendByte(uint8_t byte) 
{
    HAL_SPI_Transmit(&hspi1, &byte, 1, HAL_MAX_DELAY);
}

/******************************************************************************
 * FunctionName : W25Q16_RecvByte
 * Description  : 从W25Q16读取一个字节的数据
 * Parameters   : void
 * Returns      : uint8_t
*******************************************************************************/
uint8_t W25Q16_RecvByte(void) 
{
    uint8_t byte;
    HAL_SPI_Receive(&hspi1, &byte, 1, HAL_MAX_DELAY);
    return byte;
}
 
/******************************************************************************
 * FunctionName : W25Q16_SendRecvByte
 * Description  : 写入一个字节并同时读取一个字节
 * Parameters   : uint8_t byte
 * Returns      : uint8_t
*******************************************************************************/
uint8_t W25Q16_SendRecvByte(uint8_t byte) 
{
    uint8_t rx_byte;
    HAL_SPI_TransmitReceive(&hspi1, &byte, &rx_byte, 1, HAL_MAX_DELAY);
    return rx_byte;
}

/******************************************************************************
 * FunctionName : W25Q16_Init
 * Description  : 初始化W25Q16
 * Parameters   : void
 * Returns      : void
*******************************************************************************/
void W25Q16_Init(void) 
{
    // 初始化SPI
    // 这里可能需要调用你的SPI初始化函数
    
    // 释放掉电状态
    CS_LOW();
    W25Q16_SendByte(W25X_ReleasePowerDown);
    CS_HIGH();
    
    // 等待操作完成
    W25Q16_WaitForWriteEnd();
}

/******************************************************************************
 * FunctionName : W25Q16_ReadID
 * Description  : 读取设备ID
 * Parameters   : void
 * Returns      : uint16_t
*******************************************************************************/
uint16_t W25Q16_ReadID(void) 
{
    uint16_t Temp = 0;  
    CS_LOW();
    W25Q16_SendByte(W25X_DeviceID);
    W25Q16_SendByte(0x00);
    W25Q16_SendByte(0x00);
    W25Q16_SendByte(0x00);  
 
    Temp = W25Q16_RecvByte()<<8;
    Temp |= W25Q16_RecvByte();
 
    CS_HIGH();
    return Temp;
}

/******************************************************************************
 * FunctionName : W25Q16_WriteEnable
 * Description  : 发送写使能命令
 * Parameters   : void
 * Returns      : void
*******************************************************************************/
void W25Q16_WriteEnable(void) 
{
    CS_LOW();
    W25Q16_SendByte(W25X_WriteEnable);
    CS_HIGH();
}

/******************************************************************************
 * FunctionName : W25Q16_WriteDisable
 * Description  : 发送写禁止命令
 * Parameters   : void
 * Returns      : void
*******************************************************************************/
void W25Q16_WriteDisable(void) 
{
    CS_LOW();
    W25Q16_SendByte(W25X_WriteDisable);
    CS_HIGH();
}
 
/******************************************************************************
 * FunctionName : W25Q16_ReadSR1
 * Description  : 读取状态寄存器1
 * Parameters   : void
 * Returns      : uint8_t
*******************************************************************************/
uint8_t W25Q16_ReadSR1(void)
{  
    uint8_t byte;
    CS_LOW();
    W25Q16_SendByte(W25X_ReadStatusReg1);
    byte = W25Q16_RecvByte();
    CS_HIGH();
    return byte;
}

/******************************************************************************
 * FunctionName : W25Q16_ReadSR2
 * Description  : 读取状态寄存器2
 * Parameters   : void
 * Returns      : uint8_t
*******************************************************************************/
uint8_t W25Q16_ReadSR2(void) 
{  
    uint8_t byte;
    CS_LOW();
    W25Q16_SendByte(W25X_ReadStatusReg2);
    byte = W25Q16_RecvByte();
    CS_HIGH();
    return byte;
}

/******************************************************************************
 * FunctionName : W25Q16_WriteSR1
 * Description  : 写入状态寄存器1
 * Parameters   : uint8_t sr1
 * Returns      : void
*******************************************************************************/
void W25Q16_WriteSR1(uint8_t sr1) 
{
    W25Q16_WriteEnable();
    CS_LOW();
    W25Q16_SendByte(W25X_WriteStatusReg1);
    W25Q16_SendByte(sr1);
    CS_HIGH();
    W25Q16_WaitForWriteEnd();
}

/******************************************************************************
 * FunctionName : W25Q16_WriteSR2
 * Description  : 写入状态寄存器2
 * Parameters   : uint8_t sr2
 * Returns      : void
*******************************************************************************/
void W25Q16_WriteSR2(uint8_t sr2) 
{
    W25Q16_WriteEnable();
    CS_LOW();
    W25Q16_SendByte(W25X_WriteStatusReg2);
    W25Q16_SendByte(sr2);
    CS_HIGH();
    W25Q16_WaitForWriteEnd();
}

/******************************************************************************
 * FunctionName : W25Q16_WaitForWriteEnd
 * Description  : 等待写操作结束
 * Parameters   : void
 * Returns      : void
*******************************************************************************/
void W25Q16_WaitForWriteEnd(void) 
{
    uint32_t timeout = 0xFFFFF; // 超时计数器
    
    CS_LOW();
    W25Q16_SendByte(W25X_ReadStatusReg1); 
    
    // 等待BUSY位为0
    while((W25Q16_RecvByte() & 0x01) && (timeout--));
    
    CS_HIGH();
}


/******************************************************************************
 * FunctionName : W25Q16_Read
 * Description  : 从指定地址开始读取数据
 * Parameters   : uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead
 * Returns      : void
*******************************************************************************/
void W25Q16_Read(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead) 
{
    uint16_t i;
    CS_LOW();
    W25Q16_SendByte(W25X_ReadData);
    W25Q16_SendByte((uint8_t)((ReadAddr) >> 16));
    W25Q16_SendByte((uint8_t)((ReadAddr) >> 8));
    W25Q16_SendByte((uint8_t)ReadAddr);
    
    for(i = 0; i < NumByteToRead; i++) {
        pBuffer[i] = W25Q16_RecvByte();
    }
    
    CS_HIGH();
}

/******************************************************************************
 * FunctionName : W25Q16_PageWrite
 * Description  : 页面写入
 * Parameters   : uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite
 * Returns      : void
*******************************************************************************/
void W25Q16_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) 
{
    uint16_t i;
    
    W25Q16_WriteEnable();
    
    CS_LOW();
    W25Q16_SendByte(W25X_PageProgram);
    W25Q16_SendByte((uint8_t)((WriteAddr) >> 16));
    W25Q16_SendByte((uint8_t)((WriteAddr) >> 8));
    W25Q16_SendByte((uint8_t)WriteAddr);
    
    for(i = 0; i < NumByteToWrite; i++) {
        W25Q16_SendByte(pBuffer[i]);
    }
    
    CS_HIGH();
    W25Q16_WaitForWriteEnd();
}


/******************************************************************************
 * FunctionName : W25Q16_SectorErase
 * Description  : 扇区擦除（4KB）
 * Parameters   : uint32_t DstAddr
 * Returns      : void
*******************************************************************************/
void W25Q16_SectorErase(uint32_t DstAddr) 
{
    W25Q16_WriteEnable();
    
    CS_LOW();
    W25Q16_SendByte(W25X_SectorErase);
    W25Q16_SendByte((uint8_t)((DstAddr) >> 16));
    W25Q16_SendByte((uint8_t)((DstAddr) >> 8));
    W25Q16_SendByte((uint8_t)DstAddr);
    CS_HIGH();
    
    W25Q16_WaitForWriteEnd();
}


/******************************************************************************
 * FunctionName : W25Q16_ChipErase
 * Description  : 整片擦除
 * Parameters   : void
 * Returns      : void
*******************************************************************************/
void W25Q16_ChipErase(void) 
{
    W25Q16_WriteEnable();
    
    CS_LOW();
    W25Q16_SendByte(W25X_ChipErase);
    CS_HIGH();
    
    W25Q16_WaitForWriteEnd();
}
